package com.github.xuejike.springboot.generator;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import kotlin.jvm.internal.Intrinsics;
import kotlin.jvm.internal.Ref;
import kotlin.text.StringsKt;
import org.apache.commons.io.FileUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.io.ClassPathResource;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CodeGenMain {

    public static void main(String[] args){
        ClassPathResource resource = new ClassPathResource("config.json");
        File filePath = null;
        try {
            filePath = resource.getFile();
            String json = FileUtils.readFileToString(filePath, "UTF-8");
            System.out.println(json);
            CodeGenConfig codeGenConfig = JSON.parseObject(json, CodeGenConfig.class);
            codeGen(codeGenConfig);
        } catch (IOException e) {
            e.printStackTrace();
        }




        
    }


    public static void codeGen(CodeGenConfig config){

        //解析map
        HashMap<String, IColumnType> dbTypeMap = new HashMap<>();

        for (Map.Entry<String, String> entry : config.getDbTypeMapping().entrySet()) {
            FullNameColumnType type = new FullNameColumnType(entry.getValue());
            dbTypeMap.put(entry.getKey(),type);
        }
        HashMap<String, IEnumColumnType> enumMap = new HashMap<>();

        for (Map.Entry<String, String> entry : config.getTableColumnEnumMapping().entrySet()) {
            FullNameColumnType type = new FullNameColumnType(entry.getValue());
            type.setEnum(true);
            enumMap.put(entry.getKey(), type);
        }

        HashMap<String, IColumnType> generateMap = new HashMap<>();
        for (Map.Entry<String, String> entry : config.getGenerateMapping().entrySet()) {
            FullNameColumnType type = new FullNameColumnType(entry.getValue());
            generateMap.put(entry.getKey(), type);
        }



        JpaAutoGenerator mpg = new JpaAutoGenerator();
        mpg.setFieldTypeHandler((tableName,column)->{
            IEnumColumnType type = enumMap.get(tableName + "." + column);
            if (type != null){
                return type;
            }else if (enumMap.get(column) != null){
                return enumMap.get(column);
            }
            return null;
        });
        mpg.setFieldValueGenerationHandler((tableName,column)->{
            IColumnType type = generateMap.get(tableName + "." + column);
            if (type != null){
                return type;
            }else if (generateMap.get(column) != null){
                return generateMap.get(column);
            }
            return null;
        });

        GlobalConfig gc = new GlobalConfig();
        String projectPath = config.getPath();
        gc.setOutputDir(config.getPath() + "\\src\\main\\java");
        gc.setAuthor(config.getAuthor());
        gc.setOpen(false);
        gc.setFileOverride(true);
        mpg.setGlobalConfig(gc);
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl(config.getUrl());
        dsc.setDriverName(config.getDriverName());
        dsc.setUsername(config.getUsername());
        dsc.setPassword(config.getPwd());
        dsc.setTypeConvert(new MyTypeConvert(dbTypeMap));

        mpg.setDataSource(dsc);
        final PackageConfig pc = new PackageConfig();
        pc.setModuleName(config.getModuleName());
        pc.setParent(config.getParentPackage());
        mpg.setPackageInfo(pc);

        InjectionConfig  cfg = new InjectionConfig() {
            @Override
            public void initMap() {

            }
        };

        String templatePath = config.getSuperViewTpl();

        ArrayList focList = new ArrayList();
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(@NotNull TableInfo tableInfo) {
                // 自定义输出文件名
                return (projectPath + "/src/main/kotlin/"+pc.getParent().replace(".","/")+"/" + pc.getModuleName()
                        + "/controller/view/" + tableInfo.getEntityName() + ".kt");
            }
        });
        cfg.setFileOutConfigList((List)focList);
        mpg.setCfg((InjectionConfig)cfg);
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setEntity(config.getSuperEntityTpl());
        templateConfig.setMapper(config.getSuperDaoTpl());
        templateConfig.setService(config.getSuperServiceTpl());
        templateConfig.setController(config.getSuperControllerTpl());
        templateConfig.setServiceImpl(config.getSuperServiceImplTpl());
        templateConfig.setXml((String)null);
        mpg.setTemplate(templateConfig);
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(false);
        strategy.setSuperMapperClass(config.getSuperDaoClass());
        strategy.setSuperControllerClass(config.getSuperControllerClass());
        strategy.setSuperServiceClass(config.getSuperServiceClass());
        strategy.setSuperServiceImplClass(config.getSuperServiceImplClass());
        strategy.setInclude(config.getTableNames());
        strategy.setTablePrefix(config.getTablePreFix());
        strategy.setEntityTableFieldAnnotationEnable(true);
        strategy.setControllerMappingHyphenStyle(true);
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine((AbstractTemplateEngine)(new FreemarkerTemplateEngine()));
        mpg.execute();
    }


    static class MyTypeConvert extends MySqlTypeConvert {
        private HashMap<String,IColumnType> typeMap;

        public MyTypeConvert(HashMap<String, IColumnType> typeMap) {
            this.typeMap = typeMap;
        }

        @Override
        public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
            for (Map.Entry<String, IColumnType> entry : typeMap.entrySet()) {

                if (fieldType.contains(entry.getKey())){
                    return entry.getValue();
                }
            }

            return super.processTypeConvert(globalConfig, fieldType);
        }
    }
}
